//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package idea_dao

import (
	"context"
	"regexp"
	"time"

	"atomgit.com/openlinksaas-org/api-server/dao/db_ns"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/idea_store_api"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

type IdeaInStoreDbItem struct {
	IdeaId      string          `bson:"_id" json:"_id"`
	BasicInfo   BasicIdeaDbItem `bson:"basicInfo" json:"basicInfo"`
	IdeaStoreId string          `bson:"ideaStoreId" json:"ideaStoreId"`
	TimeStamp   int64           `bson:"timeStamp" json:"timeStamp"`
}

func (item *IdeaInStoreDbItem) ToIdeaInStore() *idea_store_api.IdeaInStore {
	return &idea_store_api.IdeaInStore{
		IdeaId: item.IdeaId,
		BasicInfo: &idea_store_api.BasicIdea{
			Title:   item.BasicInfo.Title,
			Content: item.BasicInfo.Content,
		},
		IdeaStoreId: item.IdeaStoreId,
	}
}

type _StoreIdeaDao struct {
	mc *mongo.Collection
}

func newStoreIdeaDao(db *mongo.Database) (*_StoreIdeaDao, error) {
	mc := db.Collection(db_ns.DB_NS_PROJECT_IDEA + "idea_in_store")
	_, err := mc.Indexes().CreateOne(context.Background(), mongo.IndexModel{
		Keys: bson.D{{"ideaStoreId", 1}, {"timeStamp", 1}},
	})
	if err != nil {
		return nil, err
	}
	return &_StoreIdeaDao{mc: mc}, nil
}

func (db *_StoreIdeaDao) Insert(ctx context.Context, dbItem *IdeaInStoreDbItem) error {
	_, err := db.mc.InsertOne(ctx, dbItem)
	return err
}

func (db *_StoreIdeaDao) Exist(ctx context.Context, ideaId string) (bool, error) {
	count, err := db.mc.CountDocuments(ctx, bson.M{"_id": ideaId})
	return count > 0, err
}

func (db *_StoreIdeaDao) Get(ctx context.Context, ideaId string) (*IdeaInStoreDbItem, error) {
	retItem := &IdeaInStoreDbItem{}
	err := db.mc.FindOne(ctx, bson.M{"_id": ideaId}).Decode(retItem)
	return retItem, err
}

func (db *_StoreIdeaDao) Remove(ctx context.Context, ideaId string) error {
	_, err := db.mc.DeleteOne(ctx, bson.M{"_id": ideaId})
	return err
}

func (db *_StoreIdeaDao) Count(ctx context.Context, listParam *idea_store_api.ListIdeaParam) (uint32, error) {
	query := db.genListQuery(listParam)
	count, err := db.mc.CountDocuments(ctx, query)
	return uint32(count), err
}

func (db *_StoreIdeaDao) List(ctx context.Context, listParam *idea_store_api.ListIdeaParam, offset, limit int64, order int) ([]*IdeaInStoreDbItem, error) {
	query := db.genListQuery(listParam)
	cursor, err := db.mc.Find(ctx, query, options.Find().SetSkip(offset).SetLimit(limit).SetSort(bson.M{"timeStamp": order}))
	if err != nil {
		return nil, err
	}
	retList := []*IdeaInStoreDbItem{}
	err = cursor.All(ctx, &retList)
	return retList, err
}

func (db *_StoreIdeaDao) ListByStore(ctx context.Context, ideaStoreId string) ([]*IdeaInStoreDbItem, error) {
	cursor, err := db.mc.Find(ctx, bson.M{"ideaStoreId": ideaStoreId}, options.Find().SetSort(bson.M{"timeStamp": -1}))
	if err != nil {
		return nil, err
	}
	retList := []*IdeaInStoreDbItem{}
	err = cursor.All(ctx, &retList)
	return retList, err
}

func (db *_StoreIdeaDao) ListById(ctx context.Context, ideaIdList []string) ([]*IdeaInStoreDbItem, error) {
	cursor, err := db.mc.Find(ctx, bson.M{"_id": bson.M{"$in": ideaIdList}})
	if err != nil {
		return nil, err
	}
	tmpList := []*IdeaInStoreDbItem{}
	err = cursor.All(ctx, &tmpList)
	if err != nil {
		return nil, err
	}
	tmpMap := map[string]*IdeaInStoreDbItem{}
	for _, tmpItem := range tmpList {
		tmpMap[tmpItem.IdeaId] = tmpItem
	}

	retList := []*IdeaInStoreDbItem{}
	for _, ideaId := range ideaIdList {
		tmpItem, ok := tmpMap[ideaId]
		if ok {
			retList = append(retList, tmpItem)
		}
	}
	return retList, nil
}

func (db *_StoreIdeaDao) genListQuery(listParam *idea_store_api.ListIdeaParam) bson.M {
	query := bson.M{}
	if listParam.FilterByStoreId {
		query["ideaStoreId"] = listParam.StoreId
	}
	if listParam.FilterByTitleKeyword {
		query["basicInfo.title"] = primitive.Regex{
			Pattern: regexp.QuoteMeta(listParam.TitleKeyword),
			Options: "i",
		}
	}
	return query
}

func (db *_StoreIdeaDao) UpdateBasicInfo(ctx context.Context, ideaId string, dbItem *BasicIdeaDbItem) error {
	_, err := db.mc.UpdateOne(ctx, bson.M{"_id": ideaId},
		bson.M{"$set": bson.M{"basicInfo": dbItem, "timeStamp": time.Now().UnixNano() / 1e6}})
	return err
}

func (db *_StoreIdeaDao) UpdateIdeaStore(ctx context.Context, ideaId, ideaStoreId string) error {
	_, err := db.mc.UpdateOne(ctx, bson.M{"_id": ideaId},
		bson.M{"$set": bson.M{"ideaStoreId": ideaStoreId}})
	return err
}
